/* Copyright (c) 1998 by The National Chengchi Univ. All Rights Reserved */

/***************************************************************************
   NAME
     Main.cc
   PURPOSE
     Homework assignment for complex number's operator overloading
   NOTES

   AUTHOR
     Tsai-Yen, Li   (li@nccu.edu.tw)
     Chih-Hung, Liu (s9429@cs.nccu.edu.tw)
   HISTORY
     Chih-Hung, Liu -Apr 08, 2009: Created.ex.h
***************************************************************************/

/* $Log:$ */

#include <iostream>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <vector>
#include "AnsiPrint.h"
#include "Complex.h"

using namespace std;

/**
 * Print my id 
 */

void PrintMyID(const char *studId) {
  stringstream ss;
  ss << "ID: " << studId;
  AnsiPrint(ss.str().c_str(), yellow, red, true, true);
  cout << endl << endl;

}


/**
 * Main Function Call
 */

int main() {
    ostream &os = cout;
    istream &is = cin;
    
    os << "Testing input:" << endl;
    Complex r0;
    is >> r0;
    os << r0 << endl;
    // Testing constructor
    os << "Testing constructors" << endl;
    // Testing default constructor
    Complex r1;
    os << "    Default constructor - Complex::Complex()" << endl;
    os << "\tComplex r1 = " << r1 << endl;
    assert((r1 == 0) && (r1.getReal() == 0) && (r1.getImag() == 0));

    // Testing convert constructor
    Complex r2(-3);
    os << "    Constructor - Complex::Complex(double)" << endl; 
    os << "\tComplex r2 = " << r2 << endl;
    assert((r2 == 3) && (r2.getReal() == -3.0) && (r2.getImag() == 0.0));

    // Testing regular constructor
    Complex r3(5, -12);
    os << "    Constructor - Complex::Complex(double, double)" << endl;
    os << "\tComplex r3 = " << r3 << endl;
    assert((r3 == 13) && (r3.getReal() == 5) && (r3.getImag() == -12));

    // Testing copy constructor
    Complex r4 = r3;
    os << "    Copy constructor" << endl;
    os << "\tComplex r4 = r3; r4 = " << r4 << endl;
    assert(r4 == r3);
    
    // Testing regular constructor with minus sign at numerator
    const Complex r5(-182, 63); 
    os << "    const Complex r5 = " << r5 << endl;
    assert((r5.getReal() == -182) && (r5.getImag() == 63));

    // Testing copy constructor
    Complex r6(r5);
    os << "    Complex r6(r5); r6 = " << r6 << endl;
    assert(r6 == r5);

    os << endl;


    // Testing assignment operator
    const Complex r7(50, 120);
    r4 = r7;
    r4 = r4;
    os << "Testing assignment operator" << endl;
    os << "\tr4 = 50+120i; r4 = " << r4 << endl;
    assert((r4 == 130) && (r4.getReal() == 50) && (r4.getImag() == 120));
    
    os << endl;


    // Testing arithmetic operators
    os << "Testing arithmetic operators" << endl;
    
    os << "    -(unary): \t -r5 = " << (-r5) << endl;
    assert(-r5 == Complex(-r5.getReal(), -r5.getImag() ) );
    
    os << "    +:\tr5 + r4 = " << (r5 + r4) << endl;
    assert(r5 + r4 == Complex(r5.getReal() + r4.getReal() , r5.getImag() + r4.getImag()) );
    
    os << "    -:\tr4 - r5 = " << (r4 - r5) << endl;
    assert(r4 - r5 == Complex(r4.getReal() - r5.getReal() , r4.getImag() - r5.getImag()) );
    
    os << "    *:\tr4 * r5 = " << (r4 * r5) << endl;
    assert(r4 * r5 == Complex(-16660, -18690));
    
    os << "\tr4 * 7 = " << (r4 * 7) << endl;
    assert(r4 * 7 == Complex(350, 840));
    
    os << "    /:\tr4 / r5 = " << (r4 / r5) << endl;
    assert(r4 / r5 == Complex(-1540.0/37093.0, -24990.0/37093.0) );
    
    os << "\tr4 / 5 = " << (r4 / 5) << endl;
    assert(r4 / 5 == Complex(10, 24) );
    
    r3 += r3;
    os << "    +=:\tr3 += r3; r3 = " << r3 << endl;
    assert((r3 == 26) && (r3 == Complex(10, -24)));

    r4 -= r3;
    os << "    -=:\tr4 -= r3; r4 = " << r4 << endl;
    assert(r4 == Complex(40, 144));

    r2 *= r5;
    os << "    *=:\tr2 *= r5; r2 = " << r2 << endl;
    assert(r2 == Complex(546, -189));
    
    r4 /= r2;
    os << "    /=:\tr4 /= r2; r4 = " << r4 << endl;
    assert(r4 == Complex(-5376.0/333837.0, 86184/333837.0));

    os << endl;


    // Testing prefix/postfix increment/decrement
    os << "Testing prefix/post increment/decrement" << endl;

    os << "\tr3 = " << r3 << endl;
    os << "\tr3++ = " << r3++ << endl;
    assert(r3 == Complex(11, -24));
    os << "\tr3 = " << r3 << endl;
    os << "\t++r3 = " << ++r3 << endl;
    assert(r3 == Complex(12, -24));
    os << "\tr3 = " << r3 << endl;
    os << "\t++++r3 = " << ++++r3 << endl;
    assert(r3 == Complex(14, -24));
    os << "\tr3 = " << r3 << endl;
    os << "\t----r3 = " << ----r3 << endl;
    assert(r3 == Complex(12, -24));
    os << "\tr3 = " << r3 << endl;
    os << "\tr3-- = " << r3-- << endl;
    assert(r3 == Complex(11, -24));
    os << "\t--r3 = " << --r3 << endl;
    assert(r3 == Complex(10, -24));

    ++++r3;

    os << endl;

    
    // Testing equality operators
    os << "Testing equality operators" << endl;
    // make the boolean result appear as true or false
    os << boolalpha;

    os << "\tr5 == r3 : " << (r5 == r3) << endl;
    assert(!(r5 == r3)); 
    os << "\t(r2 - r4) > r3 : " << (r2 - r4 > r3) << endl;
    assert(r2 - r4 > r3);
    os << "\t(r4 - r2) < (r3 - r2) : " << (r4 - r2 <= r3 - r2) << endl;
    assert(r4 - r2 <= r3 - r2);
    os << "\t(r2 - r3 != r3) : " << (r2 - r3 != r3) << endl;
    assert(r2 - r3 != r3);
    Complex r(224,422), p(224,422);
    os << "\t224 + 422i == 224 + 422i : " << ( p == r ) << endl;
    assert( p == r );
    Complex q(224, 421);
    os << "\t224 + 422i > " << q << " : " << (r > q) << endl;
    assert( r > q );
    Complex s(224, 423);
    os << "\t224 + 422i < " << s << " : " << (r < s) << endl;
    assert( r < s );
    Complex t(225, 422);
    os << "\t224 + 422i < " << t << " : " << (r < t) << endl;
    assert( r < t );
    Complex u(223, 422);
    os << "\t224 + 422i > " << u << " : " << (r > u) << endl;
    assert( r > u );
    Complex a(225, 423);
    os << "\t224 + 422i < " << a << " : " << (r < a) << endl;
    assert( r < a );
    Complex b(223, 423);
    os << "\t224 + 422i > " << b << " : " << (r > b) << endl;
    assert( r > b );
    Complex c(223, 421);
    os << "\t224 + 422i > " << c << " : " << (r > c) << endl;
    assert( r > c );
    Complex d(225, 421);
    os << "\t224 + 422i < " << d << " : " << (r < d) << endl;
    assert( r < d );
    
    os << endl;
    

    // General test
    os << "General test" << endl;

    r2 = r3 = r1 += r5 * r3;
    os << "\tr2 = r3 = r1 += r5 * r3; r4 = " << r4 << ", r1 = " << r1 << endl;
    assert(r1 == Complex(-672, 5124) && r3 == Complex(-672, 5124));

    // Test for conjugate

    Complex r8(5566, 7788);
    os << "\tr8 is " << r8 << " and its conjugate is " << r8.conjugate() << endl;
    assert(r8.conjugate() == Complex(5566, -7788));
    
    os << "\t224 + 422i adds its conjugate is " << (r + r.conjugate() ) << endl;
    assert( (r + r.conjugate()) == Complex(448,0) );

    os << "\t224 + 422i subtracts its conjugate is " << (r - r.conjugate() ) << endl;
    assert( (r - r.conjugate()) == Complex(0,844) );
    
    os << "\t224 + 422i add its conjugate 's absolute values are same ? " << (r.absolute() == r.conjugate().absolute()) << endl;
    assert(r.absolute() == r.conjugate().absolute());
    
    os << noboolalpha << endl << endl;

   

    // Test for dynamic allocation => you should write Copy Constructor, Assignment Operator, and Destructor
    
    os << "Dynamic Allocation Test:" << endl;

    vector <Complex*> complexes;
    
    os << "\tAllocating 1000000 Complex numbers, be patient..." << endl;
    for(int i = 0; i < 1000000; i++){
        complexes.push_back(new Complex(10, 30));
    }

    Complex tmp;

    os << "\tSum them up !! Now release your anger...and wait..." << endl;
    for(size_t i = 0; i < complexes.size(); i++){
        tmp += *(complexes.at(i));
    }

    os << "\tNow we release the dark side of the memory force..." << endl;
    while(!complexes.empty()){
        delete complexes.at(complexes.size() - 1);
        complexes.pop_back();
    }

    os << "\tFinally, fulfill your destiny !! The result is:" << endl;
    os << "\t" << tmp << endl << endl;
    assert((tmp == Complex(10000000, 30000000)));
    os << "\tCongratulation, you pass the test of the dark side, now face your destiny." << endl << endl;

    PrintMyID("98703060");

    return 0;

}
